﻿using NPOI.SS.Formula.Functions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CAPTS_Suite
{
    internal class OneChamber
    {
		public int caseindex;//标识箱子序号
		public DateTime start_time;
		public DateTime end_time;

        //用于暂存一次测量4个循环数据显示在视图中
        public List<double> data_CO2_4 = new List<double>();
        public List<double> data_H2O_4 = new List<double>();
        public List<double> data_CH4_4 = new List<double>();
        public List<double> data_N2O_4 = new List<double>();
        public List<double> data_NH3_4 = new List<double>();
        public List<DateTime> time_4 = new List<DateTime>();

        //拟合斜率
        public double slope_co2;
		public double slope_h2o;
        public double slope_ch4;
        public double slope_n2o;
        public double slope_nh3;


        //general data
        public double time; // unit: second. 
		public bool LinearSelect; // true: selected, false: not selected. 
		public bool QuaSelect;  // true: selected, false: not selected.

        public double AcR2; // R2 for linear fitting Ac to seconds
        public double EcR2; // R2 for linear fitting Ac to seconds
        public double MerR2; // R2 for linear fitting Ac to seconds
        public double N2oR2; // R2 for linear fitting Ac to seconds


        public double AcQuaR2; // R2 for Quadratic fitting Ac to seconds
        public double CvPPFD; //  coefficient of variation for PPFD. 

        //Linear Fitting Data result
        public double Ac_Li; // canopy photosynthesis rate
		public double Ec_Li; // canopy transpiration rate
        public double MER_Li; // Methane emission rate
        public double N2OER_Li; // Nitrous oxide emission rate
		public double NH3ER_PI;

        //Quadratic Fitting Data result
		public double QuaDydx_start; // The deriative of the starting point of the quadratic equation 
        public double Ac_Qua; // canopy photosynthesis rate
        public double Ec_Qua; // canopy transpiration rate
        public double MER_Qua; // Methane emission rate
        public double N2OER_Qua; // Nitrous oxide emission rate
		public double NH3ER_Qua;

        public bool ZeroingFlag; // flag of zero during this measurement.
		public bool deteleFlag = false;//如果是数据分析则先进行数据清洗再拟合，不用进一步数据清洗（删除前后数据）

		private DataLine avgData = new DataLine();

		private List<DataLine> gData_list = new List<DataLine>(); // good data
		private List<DataLine> rawData_list = new List<DataLine>(); // raw data, 保存原始数据，全部测量数据的，包括4次loop的都保存到这里，每条数据又loopID


		// raw data of uV, only in 2016 version CAPTS has the following data. 
		private List<DataLine> uVdata_list = new List<DataLine>(); // uV data. seconds is not used. 

		public OneChamber()
        {
			LinearFitInit();
			QuaFitInit();
        }

		public void LinearFitInit()
		{
			if (LinearSelect == true)
			{
				Ac_Li = 0; // default value
				Ec_Li = 0; // default value
				MER_Li = 0; // default value
				N2OER_Li = 0; // default value
				NH3ER_PI = 0;
            }
        }

        public void QuaFitInit()
        {
			if (QuaSelect == true)
			{
                Ac_Qua = 0; // default value
                Ec_Qua = 0; // default value
                MER_Qua = 0; // default value
				N2OER_Qua = 0; // default value
				NH3ER_Qua = 0;
            }
        }
        static double CalculateR2(List<double> x, List<double> y)
        {
            int n = y.Count;
            double xMean = x.Average();
            double yMean = y.Average();

            // Calculate Sxy and Sxx
            double sxy = 0;
            double sxx = 0;
            for (int i = 0; i < n; i++)
            {
                sxy += (x[i] - xMean) * (y[i] - yMean);
                sxx += (x[i] - xMean) * (x[i] - xMean);
            }

            // Calculate slope (b1) and intercept (b0)
            double b1 = sxy / sxx;
            double b0 = yMean - b1 * xMean;

            // Calculate SST and SSR
            double ssTotal = 0;
            double ssReg = 0;
            for (int i = 0; i < n; i++)
            {
                double yPredicted = b0 + b1 * x[i];
                ssTotal += (y[i] - yMean) * (y[i] - yMean);
                ssReg += (yPredicted - yMean) * (yPredicted - yMean);
            }

            return ssReg / ssTotal;
        }
        public void updateForSBA5()
        {

            int preDelation = Setting.PRE_DELETE_TIME;
            int dataLength = Setting.LINEAR_FIT_DURATION;
            int k = 0; // 用于单个loop的数据的从前往后计数，每个loop开始时候重置为0
            for (int i = 0; i < rawData_list.Count; i++)
            {
                if (k < preDelation) // 去掉前部数据
                {
                    k++;
                    continue;
                }
                else if (k >= preDelation && k < preDelation + dataLength) //保留中间的目标数据
                {
                    DataLine dl = new DataLine();
                    dl.copyData(rawData_list[i].time_string, rawData_list[i].seconds, rawData_list[i].co2, rawData_list[i].ch4, rawData_list[i].n2o, rawData_list[i].h2o, rawData_list[i].nh3, rawData_list[i].temperature, rawData_list[i].air_pressure,
                                            ((rawData_list[i].ppfd <= 3000) ? rawData_list[i].ppfd : 0), rawData_list[i].relative_humidity);  // ppfd < 3000, or set 0. 
                    gData_list.Add(dl);
                    k++;
                }
                else if (k >= preDelation + dataLength) // 去掉尾部数据（一般不用去掉）
                {
                    k++;
                    continue;
                }
            }
            //记录时间
            start_time = Convert.ToDateTime(gData_list[0].time_string);
            end_time = Convert.ToDateTime(gData_list[gData_list.Count - 1].time_string);

            // 线性拟合得到斜率
            // 使用gData_list数据进行线性拟合
            List<double> co2_v = new List<double>();
            List<double> seconds_v = new List<double>();
            List<double> ppfd_v = new List<double>();
            List<double> temp_v = new List<double>();
            List<double> pressure_v = new List<double>();
            List<double> rh_v = new List<double>();
            List<double> h2o_v = new List<double>();
            List<double> ch4_v = new List<double>();
            List<double> n2o_v = new List<double>();
            List<double> nh3_v = new List<double>();

            for (int n = 0; n < gData_list.Count; n++)
            {
                seconds_v.Add((double)(gData_list[n].seconds));
                co2_v.Add(gData_list[n].co2);
                ppfd_v.Add(gData_list[n].ppfd);
                temp_v.Add(gData_list[n].temperature);
                pressure_v.Add(gData_list[n].air_pressure);
                rh_v.Add(gData_list[n].relative_humidity);
                h2o_v.Add(gData_list[n].h2o);
                ch4_v.Add(gData_list[n].ch4);
                n2o_v.Add(gData_list[n].n2o);
                nh3_v.Add(gData_list[n].nh3);
                //Console.WriteLine("seconds:" + gData_list[n].seconds + "    co2:" + gData_list[n].co2 + "    h2o:" + gData_list[n].h2o + "    ch4:" + gData_list[n].ch4 + "    n2o:" + gData_list[n].n2o + "    nh3:" + gData_list[n].nh3);
            }

            ///////////////////////////////////////////////////////////////////////////////
            /* ------------------------------Linear Fit fo gas Concentration-------------------------*/
            preprocess.Fit LiFit = new preprocess.Fit();
            LinearSelect = true;
            LiFit.linearFit(seconds_v, co2_v, gData_list.Count); // calculate the linear fit of Ac and time(second). 
            AcR2 = CalculateR2(seconds_v, co2_v);
            slope_co2 = LiFit.getSlope();
            //Console.WriteLine("slope_co2:" + slope_co2 + "     rmse:" + LiFit.getR_square());
            double intercept = LiFit.getIntercept();
            if (AcR2 < Setting.R2_CUTOFF_CO2FIT)
            {  // for cutoff check of R2, set select. 
                LinearSelect = false; // lable this measurement
            }
            LiFit.linearFit(seconds_v, h2o_v, gData_list.Count); // calculate the linear fit of Ac and time(second). 
            EcR2 = CalculateR2(seconds_v, h2o_v);
            slope_h2o = LiFit.getSlope();
            LiFit.linearFit(seconds_v, ch4_v, gData_list.Count);
            MerR2 = CalculateR2(seconds_v, ch4_v);
            slope_ch4 = LiFit.getSlope();
            LiFit.linearFit(seconds_v, n2o_v, gData_list.Count);
            N2oR2 = CalculateR2(seconds_v, n2o_v);
            slope_n2o = LiFit.getSlope();
            Console.WriteLine("slope_co2:" + slope_co2 + "; slope_h2o:" + slope_h2o + "slope_ch4:" + slope_ch4 + "slope_n2o:" + slope_n2o);
            LiFit.linearFit(seconds_v, nh3_v);
            slope_nh3 = LiFit.getSlope();

            sqf.Statistic sta = new sqf.Statistic();
            CvPPFD = sta.calcCV(ppfd_v); // calcualte the ST_ERROR of PPFD  0-100, unit: %
            // calculate averaged data

            avgData.seconds = (int)sta.calcMean(seconds_v);

            String temp = ((int)avgData.seconds / 3600).ToString();
            temp += ":";
            temp += ((int)(avgData.seconds % 3600) / 60).ToString();
            temp += ":";
            temp += ((avgData.seconds % 3600) % 60).ToString();
            avgData.time_string = temp;

            avgData.ppfd = sta.calcMean(ppfd_v);
            avgData.co2 = sta.calcMean(co2_v);
            if (avgData.co2 < 0 || avgData.co2 > 2000) { avgData.co2 = 0; }
            avgData.co2_StdDev = sta.calcStdDev(co2_v);

            avgData.ch4 = sta.calcMean(ch4_v);
            //if (avgData.ch4 < 0 || avgData.ch4 > 2000) { avgData.ch4 = 0; }
            avgData.ch4_StdDev = sta.calcStdDev(ch4_v);

            avgData.temperature = sta.calcMean(temp_v);
            if (avgData.temperature < 0 || avgData.temperature > 100) { avgData.temperature = 0; }
            avgData.air_pressure = sta.calcMean(pressure_v);
            if (avgData.air_pressure < 50) { avgData.air_pressure = 0; }
            avgData.relative_humidity = sta.calcMean(rh_v);
            if (avgData.relative_humidity < 0 || avgData.relative_humidity > 100) { avgData.relative_humidity = 0; }
            avgData.h2o = sta.calcMean(h2o_v);
            avgData.h2o_StdDev = sta.calcStdDev(h2o_v);
            //if (avgData.h2o < 0 || avgData.h2o > 40) { avgData.h2o = 0; }
            avgData.n2o = sta.calcMean(n2o_v);
            avgData.n2o_StdDev = sta.calcStdDev(n2o_v);
            avgData.nh3 = sta.calcMean(nh3_v);
            avgData.nh3_StdDev = sta.calcStdDev(nh3_v);

            // calculate Ac and Ec
            // Ac = (dc/dt) * V * Pa / (S * R * T) 
            double R = 8.3e-3; // universal gas constant
            double temperature = avgData.temperature;
            double pressure = avgData.air_pressure;

            if (Setting.pressureType == 0)
            {
                pressure = Setting.AIR_PRESSURE_DEFAULT;
            }
            if (Setting.temperatureType == 0)
            {
                temperature = Setting.TEMPERATURE_DEFAULT;
            }
            Ac_Li = -slope_co2 * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
            Ec_Li = slope_h2o * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
            MER_Li = slope_ch4 * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
            N2OER_Li = slope_n2o * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
            NH3ER_PI = slope_nh3 * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);

        }
        public void updateFor4Loops()
        {

            int preDelation = Setting.PRE_DELETE_TIME;
            int dataLength = Setting.LINEAR_FIT_DURATION;
            int k = 0; // 用于单个loop的数据的从前往后计数，每个loop开始时候重置为0
            int currentLoop = 1; //用于记录当前的loopID

            for (int i = 0; i < rawData_list.Count; i++)
            {
                if (rawData_list[i].currentLoop != currentLoop)
                {
                    currentLoop = rawData_list[i].currentLoop;
                    k = 0;
                }

                if (k < preDelation) // 去掉前部数据
                {
                    k++;
                    continue;
                }
                else if (k >= preDelation && k < preDelation + dataLength) //保留中间的目标数据
                {
                    DataLine dl = new DataLine();
                    dl.copyData(rawData_list[i].time_string, rawData_list[i].seconds, rawData_list[i].co2, rawData_list[i].ch4, rawData_list[i].n2o, rawData_list[i].h2o, rawData_list[i].nh3, rawData_list[i].temperature, rawData_list[i].air_pressure,
                                            ((rawData_list[i].ppfd <= 3000) ? rawData_list[i].ppfd : 0), rawData_list[i].relative_humidity);  // ppfd < 3000, or set 0. 
                    gData_list.Add(dl);
                    k++;
                }
                else if (k >= preDelation + dataLength) // 去掉尾部数据（一般不用去掉）
                {
                    k++;
                    continue;
                }
            }
            //记录时间
            start_time = Convert.ToDateTime(gData_list[0].time_string);
            end_time = Convert.ToDateTime(gData_list[gData_list.Count - 1].time_string);

            // 线性拟合得到斜率
            // 使用gData_list数据进行线性拟合
            List<double> co2_v = new List<double>();
            List<double> seconds_v = new List<double>();
            List<double> ppfd_v = new List<double>();
            List<double> temp_v = new List<double>();
            List<double> pressure_v = new List<double>();
            List<double> rh_v = new List<double>();
            List<double> h2o_v = new List<double>();
            List<double> ch4_v = new List<double>();
            List<double> n2o_v = new List<double>();
            List<double> nh3_v = new List<double>();

            for (int n = 0; n < gData_list.Count; n++)
            {
                seconds_v.Add((double)(gData_list[n].seconds));
                co2_v.Add(gData_list[n].co2);
                ppfd_v.Add(gData_list[n].ppfd);
                temp_v.Add(gData_list[n].temperature);
                pressure_v.Add(gData_list[n].air_pressure);
                rh_v.Add(gData_list[n].relative_humidity);
                h2o_v.Add(gData_list[n].h2o);
                ch4_v.Add(gData_list[n].ch4);
                n2o_v.Add(gData_list[n].n2o);
                nh3_v.Add(gData_list[n].nh3);
                //Console.WriteLine("seconds:" + gData_list[n].seconds + "    co2:" + gData_list[n].co2 + "    h2o:" + gData_list[n].h2o + "    ch4:" + gData_list[n].ch4 + "    n2o:" + gData_list[n].n2o + "    nh3:" + gData_list[n].nh3);
            }

            ///////////////////////////////////////////////////////////////////////////////
            /* ------------------------------Linear Fit fo gas Concentration-------------------------*/
            preprocess.Fit LiFit = new preprocess.Fit();
            LinearSelect = true;
            LiFit.linearFit(seconds_v, co2_v, gData_list.Count); // calculate the linear fit of Ac and time(second). 
            AcR2 = CalculateR2(seconds_v, co2_v);
            slope_co2 = LiFit.getSlope();
            //Console.WriteLine("slope_co2:" + slope_co2 + "     rmse:" + LiFit.getR_square());
            double intercept = LiFit.getIntercept();
            if (AcR2 < Setting.R2_CUTOFF_CO2FIT)
            {  // for cutoff check of R2, set select. 
                LinearSelect = false; // lable this measurement
            }
            LiFit.linearFit(seconds_v, h2o_v, gData_list.Count); // calculate the linear fit of Ac and time(second). 
            EcR2 = CalculateR2(seconds_v, h2o_v);
            slope_h2o = LiFit.getSlope();
            LiFit.linearFit(seconds_v, ch4_v, gData_list.Count);
            MerR2 = CalculateR2(seconds_v, ch4_v);
            slope_ch4 = LiFit.getSlope();
            LiFit.linearFit(seconds_v, n2o_v, gData_list.Count);
            N2oR2 = CalculateR2(seconds_v, n2o_v);
            slope_n2o = LiFit.getSlope();
            Console.WriteLine("slope_co2:" + slope_co2 + "; slope_h2o:" + slope_h2o + "slope_ch4:" + slope_ch4 + "slope_n2o:" + slope_n2o);
            LiFit.linearFit(seconds_v, nh3_v);
            slope_nh3 = LiFit.getSlope();

            sqf.Statistic sta = new sqf.Statistic();
            CvPPFD = sta.calcCV(ppfd_v); // calcualte the ST_ERROR of PPFD  0-100, unit: %
            // calculate averaged data

            avgData.seconds = (int)sta.calcMean(seconds_v);

            String temp = ((int)avgData.seconds / 3600).ToString();
            temp += ":";
            temp += ((int)(avgData.seconds % 3600) / 60).ToString();
            temp += ":";
            temp += ((avgData.seconds % 3600) % 60).ToString();
            avgData.time_string = temp;

            avgData.ppfd = sta.calcMean(ppfd_v);
            avgData.co2 = sta.calcMean(co2_v);
            if (avgData.co2 < 0 || avgData.co2 > 2000) { avgData.co2 = 0; }
            avgData.co2_StdDev = sta.calcStdDev(co2_v);

            avgData.ch4 = sta.calcMean(ch4_v);
            //if (avgData.ch4 < 0 || avgData.ch4 > 2000) { avgData.ch4 = 0; }
            avgData.ch4_StdDev = sta.calcStdDev(ch4_v);

            avgData.temperature = sta.calcMean(temp_v);
            if (avgData.temperature < 0 || avgData.temperature > 100) { avgData.temperature = 0; }
            avgData.air_pressure = sta.calcMean(pressure_v);
            if (avgData.air_pressure < 50) { avgData.air_pressure = 0; }
            avgData.relative_humidity = sta.calcMean(rh_v);
            if (avgData.relative_humidity < 0 || avgData.relative_humidity > 100) { avgData.relative_humidity = 0; }
            avgData.h2o = sta.calcMean(h2o_v);
            avgData.h2o_StdDev = sta.calcStdDev(h2o_v);
            //if (avgData.h2o < 0 || avgData.h2o > 40) { avgData.h2o = 0; }
            avgData.n2o = sta.calcMean(n2o_v);
            avgData.n2o_StdDev = sta.calcStdDev(n2o_v);
            avgData.nh3 = sta.calcMean(nh3_v);
            avgData.nh3_StdDev = sta.calcStdDev(nh3_v);

            // calculate Ac and Ec
            // Ac = (dc/dt) * V * Pa / (S * R * T) 
            double R = 8.3e-3; // universal gas constant
            double temperature = avgData.temperature;
            double pressure = avgData.air_pressure;

            if (Setting.pressureType == 0)
            {
                pressure = Setting.AIR_PRESSURE_DEFAULT;
            }
            if (Setting.temperatureType == 0)
            {
                temperature = Setting.TEMPERATURE_DEFAULT;
            }
            Ac_Li = -slope_co2 * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
            Ec_Li = slope_h2o * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
            MER_Li = slope_ch4 * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
            N2OER_Li = slope_n2o * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
            NH3ER_PI = slope_nh3 * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);

        }
        public void update() // 筛选+拟合计算，当4次循环结束后调用，仅调用一次即可
		{
			LinearSelect = true;//线性拟合置为"是"
            // check raw data vector length, check whether full and complete measurement? 
            // if NOT, set select to be false
            if (rawData_list.Count < Setting.LOG_DURATION_CUTOFF) // 实际数据长度小于设定的使用数据长度
			{
                LinearSelect = false;
                QuaSelect = false;
            }
			
			// delete some data in begining and fix length for data used for linear fit. 
			// based on Setting
			for (int i = 0; i < rawData_list.Count; i++)
			{
				DataLine dl = new DataLine();
				
				dl.copyData(rawData_list[i].time_string, rawData_list[i].seconds, rawData_list[i].co2, rawData_list[i].ch4, rawData_list[i].n2o, rawData_list[i].h2o, rawData_list[i].nh3,  rawData_list[i].temperature, rawData_list[i].air_pressure,
					((rawData_list[i].ppfd <= 3000) ? rawData_list[i].ppfd : 0), rawData_list[i].relative_humidity);  // ppfd < 3000, or set 0. 
				gData_list.Add(dl);
                //Console.WriteLine("n2o:"+ rawData_list[i].n2o);
            }
			//若未进行数据清洗则进行数据清洗
			if(deteleFlag == false)
			{
				Console.WriteLine("进行数据清洗");
                if (LinearSelect)
                {
                    try
                    {
                        if (Setting.PRE_DELETE_TIME - 1 >= 0 && Setting.PRE_DELETE_TIME - 1 <= gData_list.Count)
                        {
                            gData_list.RemoveRange(0, Setting.PRE_DELETE_TIME - 1);// delete the begining elements.
                            // C++ code: gData_list.erase(gData_list.begin(), gData_list.begin() + Setting::PRE_DELETE_TIME - 1); // delete the begining elements. 

                        }

                    }
                    catch { }
                                                        
                    if (gData_list.Count > Setting.LINEAR_FIT_DURATION)
                    {
                        gData_list.RemoveRange(Setting.LINEAR_FIT_DURATION, gData_list.Count - Setting.LINEAR_FIT_DURATION); // delete the ending elements, only keep the linear fitting length. 
                    }
                    else
                    {
                        Console.WriteLine("short vector!");
                    }
                }
            }
			// delete warm up data

			// v1.1
			
			if (LinearSelect)
			{

				int zeroFrom = 0, zeroTo = 0;
				bool findZero = false;

				double d = System.Math.Abs(gData_list[0].co2 - gData_list[gData_list.Count - 1].co2);
				double d_ch4 = System.Math.Abs(gData_list[0].ch4 - gData_list[gData_list.Count - 1].ch4);

                double scaleIdx = 0.5;

				for (int i = 0; i < gData_list.Count - 1; i++)
				{

					if (gData_list[i].co2 < 20)
					{  // delete the warm up data
						LinearSelect = false; // label this measurement
						QuaSelect = false; // label this measurement
						ZeroingFlag = true; // there is zeroing during this measurement. 
						break;
					}

                    // inserted bugs here
					if (gData_list[i].ch4 < 20)
                    {  // delete the warm up data
                        LinearSelect = false; // label this measurement
						QuaSelect = false; // label this measurement
                        ZeroingFlag = true; // there is zeroing during this measurement. 
                        break;
                    }
					
                    for (int j = i + 1; j < gData_list.Count; j++)
					{

						if (System.Math.Abs(gData_list[j].co2 - gData_list[i].co2) > (j - i) * d * scaleIdx)
						{

							if ((i == 0 || j == gData_list.Count - 1) && j - i > 4)
							{  // zeroing at begining or end. continue 3 same value will be deleted.
								zeroFrom = i; zeroTo = j;
								gData_list.RemoveRange(zeroFrom, zeroTo - zeroFrom);

								findZero = true;
							}
							else if (j - i > 20)
							{  // zeroing in the middle of a measurement. continue 5 same value will be deleted.
								zeroFrom = i; zeroTo = j;
								gData_list.RemoveRange(zeroFrom, zeroTo - zeroFrom);

								findZero = true;
							}
							break;
						}
					}

					if (findZero)
					{
						ZeroingFlag = true; // there is zeroing during this measurement. 
						LinearSelect = false; // label this measurement
						QuaSelect = false; // label this measurement
						break;
					}
				}
			}
			

			///////////////////////// put data into individual vectors ////////////////////
			List<double> co2_v = new List<double>();
			List<double> seconds_v = new List<double>();
			List<double> ppfd_v = new List<double>();
			List<double> temp_v = new List<double>();
			List<double> pressure_v = new List<double>();
			List<double> rh_v = new List<double>();
			List<double> h2o_v = new List<double>();
			List<double> ch4_v = new List<double>();
            List<double> n2o_v = new List<double>();
			List<double> nh3_v = new List<double>();

            for (int n = 0; n < gData_list.Count; n++)
			{
				seconds_v.Add((double)(gData_list[n].seconds));
				co2_v.Add(gData_list[n].co2);
				ppfd_v.Add(gData_list[n].ppfd);
				temp_v.Add(gData_list[n].temperature);
				pressure_v.Add(gData_list[n].air_pressure);
				rh_v.Add(gData_list[n].relative_humidity);
				h2o_v.Add(gData_list[n].h2o);
                ch4_v.Add(gData_list[n].ch4);
                n2o_v.Add(gData_list[n].n2o);
				nh3_v.Add(gData_list[n].nh3);
                //Console.WriteLine("seconds:" + gData_list[n].seconds + "    co2:" + gData_list[n].co2 + "    h2o:" + gData_list[n].h2o + "    ch4:" + gData_list[n].ch4 + "    n2o:" + gData_list[n].n2o + "    nh3:" + gData_list[n].nh3);
            }

            ///////////////////////////////////////////////////////////////////////////////
            /* ------------------------------Linear Fit fo gas Concentration-------------------------*/
            preprocess.Fit LiFit = new preprocess.Fit();
			LinearSelect = true;
            LiFit.linearFit(seconds_v, co2_v); // calculate the linear fit of Ac and time(second). 
			AcR2 = LiFit.getR_square();  // store the Ac R2 of the fitting of this measurement. 
			double slope_co2 = LiFit.getSlope();
            //Console.WriteLine("slope_co2:" + slope_co2 + "     rmse:" + LiFit.getR_square());
            double intercept = LiFit.getIntercept();
			if (AcR2 < Setting.R2_CUTOFF_CO2FIT)
			{  // for cutoff check of R2, set select. 
                LinearSelect = false; // lable this measurement
            }
            LiFit.linearFit(seconds_v, h2o_v); // calculate the linear fit of Ac and time(second). 
			double slope_h2o = LiFit.getSlope();
            LiFit.linearFit(seconds_v, ch4_v); 
            double slope_ch4 = LiFit.getSlope();
            LiFit.linearFit(seconds_v, n2o_v);
            double slope_n2o = LiFit.getSlope();
            Console.WriteLine("slope_co2:" + slope_co2 + "; slope_h2o:" + slope_h2o + "slope_ch4:" + slope_ch4 + "slope_n2o:" + slope_n2o);
            LiFit.linearFit(seconds_v, nh3_v);
            double slope_nh3 = LiFit.getSlope();

			/* ------------------------------Quadratic Fit fo gas Concentration-------------------------*/
			preprocess.Fit QuaFit = new preprocess.Fit();
			QuaSelect = true;
			QuaFit.QuaFit(seconds_v, h2o_v); // calculate the Quadratic fit of Ac and time(second).
			double slope_h2o_qua = 2 * QuaFit.getQuaFactor(0) * h2o_v[0] + QuaFit.getQuaFactor(1);
			QuaFit.QuaFit(seconds_v, co2_v); // calculate the Quadratic fit of Ac and time(second).
			double slope_co2_qua = 2 * QuaFit.getQuaFactor(0) * co2_v[0] + QuaFit.getQuaFactor(1);
			AcQuaR2 = QuaFit.getR_square();

			QuaFit.QuaFit(seconds_v, ch4_v); // calculate the Quadratic fit of Ac and time(second).
			double slope_ch4_qua = 2 * QuaFit.getQuaFactor(0) * ch4_v[0] + QuaFit.getQuaFactor(1);
			QuaFit.QuaFit(seconds_v, n2o_v); // calculate the Quadratic fit of Ac and time(second).
			double slope_n2o_qua = 2 * QuaFit.getQuaFactor(0) * n2o_v[0] + QuaFit.getQuaFactor(1);
			QuaFit.QuaFit(seconds_v, nh3_v); // calculate the Quadratic fit of Ac and time(second).
			double slope_nh3_qua = 2 * QuaFit.getQuaFactor(0) * nh3_v[0] + QuaFit.getQuaFactor(1);
			sqf.Statistic sta = new sqf.Statistic();
			CvPPFD = sta.calcCV(ppfd_v); // calcualte the ST_ERROR of PPFD  0-100, unit: %
			if (CvPPFD > Setting.CV_CUTOFF_PPFD)
			{        // for cutoff check of ST_ERROR of PPFD, set select
				LinearSelect = false;
			}

			// calculate averaged data

			avgData.seconds = (int)sta.calcMean(seconds_v);
			
			String temp = ((int)avgData.seconds / 3600).ToString();
			temp += ":";
			temp += ((int)(avgData.seconds % 3600) / 60).ToString();
			temp += ":";
			temp += ((avgData.seconds % 3600) % 60).ToString();
			avgData.time_string = temp;

            avgData.ppfd = sta.calcMean(ppfd_v);
            avgData.co2 = sta.calcMean(co2_v);
            if (avgData.co2 < 0 || avgData.co2 > 2000) { avgData.co2 = 0; }
            avgData.ch4 = sta.calcMean(ch4_v);
			//if (avgData.ch4 < 0 || avgData.ch4 > 2000) { avgData.ch4 = 0; }
			avgData.temperature = sta.calcMean(temp_v);
			if (avgData.temperature < 0 || avgData.temperature > 100) { avgData.temperature = 0; }
			avgData.air_pressure = sta.calcMean(pressure_v);
			if (avgData.air_pressure < 50) { avgData.air_pressure = 0; }
			avgData.relative_humidity = sta.calcMean(rh_v);
			if (avgData.relative_humidity < 0 || avgData.relative_humidity > 100) { avgData.relative_humidity = 0; }
			avgData.h2o = sta.calcMean(h2o_v);
			//if (avgData.h2o < 0 || avgData.h2o > 40) { avgData.h2o = 0; }
			avgData.n2o = sta.calcMean(n2o_v);
            avgData.nh3 = sta.calcMean(nh3_v);

            // Linear and Quadratic Fitting result


            // calculate Ac and Ec
            // Ac = (dc/dt) * V * Pa / (S * R * T) 
            double R = 8.3e-3; // universal gas constant
			double temperature = avgData.temperature;
			double pressure = avgData.air_pressure;

			if (Setting.pressureType == 0)
			{
				pressure = Setting.AIR_PRESSURE_DEFAULT;
			}
			if (Setting.temperatureType == 0)
			{
				temperature = Setting.TEMPERATURE_DEFAULT;
			}
			Ac_Li = -slope_co2 * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
			Ec_Li = slope_h2o * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
            MER_Li = slope_ch4 * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
            N2OER_Li = slope_n2o * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
            NH3ER_PI = slope_nh3 * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);

			Ac_Qua = -slope_co2_qua * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
			Ec_Qua = slope_h2o_qua * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
			MER_Qua = slope_ch4_qua * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
			N2OER_Qua = slope_n2o_qua * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);
			NH3ER_Qua = slope_nh3_qua * Setting.CHAMBER_VOLUMN / Setting.CHAMBER_GROUND_AREA * pressure / R / (temperature + 273.16);


			//         if (Setting.MACHINE_VERSION == 7810)
			//{
			//	if (Ac_Li > 300 || Ac_Li < -300)
			//	{  // Strange value of Ac. 
			//	   LinearSelect = false;
			//	   QuaSelect = false;
			//	}
			//}

			// Qingfeng add here for Li6400 version, bu chang proportionally to Ac. because Li6400 pump in the gas with ambient CO2 concentration.
			if (Setting.CAPTS_VERSION == 1)
			{
				double theta = Setting.PUMP_FLOW_RATE * Setting.LOG_DURATION_CUTOFF / (Setting.CHAMBER_VOLUMN * 1000) / 60 / 2;  // refer to Qingfeng Eqn. 
				Ac_Li = Ac_Li * (1 + theta);
				Ec_Li = Ec_Li * (1 + theta);
			}

			if (Ac_Li > 500 || Ac_Li < -500)
			{  // Strange value of Ac. 
			   //5		select = false;
			}
			deteleFlag = false;
		}

		public DataLine get_avgData()
		{
			return avgData;
		}

		public List<DataLine> get_goodDataList()
		{
			return gData_list;
		}

		public void add_goodData(DataLine dc_ptr)
		{
			gData_list.Add(dc_ptr);
		}

		public List<DataLine> get_rawDataList()
		{
			return rawData_list;
		}

		public void add_rawData(DataLine dc_ptr)
		{

			rawData_list.Add(dc_ptr);

		}

		public List<DataLine> get_uVdataList()
		{
			return uVdata_list;
		}

		
		public void add_uVdata(DataLine dc_ptr)
		{
			uVdata_list.Add(dc_ptr);
		}


	}
}
